package tracer;

import io.ReadXML;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import primitives.World3D;
import ray.Ray;
import surface.ImageProducer;
import bitmap.Bitmap;
import bitmap.BitmapIO;
import camera.Camera;
import colour.Colour;

/**
 * This is the class for the integrated excution including the xml read,command
 * param input, the final image calculation
 * 
 * @author Yuting Wu
 * @author Kan Lin
 * @author Bing Dong
 * 
 */
public class RayTracerRunning extends Thread {

	

	/**
	 * Read data from xml file and calculate the pixel matrics
	 */
	public void runTracer(int imgWidth, int imgHeight, int picWidth,
			int picHeight, int threadNum, double zoom, String fileRead,
			String fileWrite, boolean ifShadowAndReflect, int reflectionDepth) {
		
		try {

			XMLReader parser = XMLReaderFactory.createXMLReader();
			ReadXML contentHandler = new ReadXML();
			parser.setContentHandler(contentHandler);

			parser.parse(fileRead);
			World3D world = contentHandler.getWorld3D();
			Camera ca = world.getCamera();
			// AbstractShape d = new AbstractShape(new
			// Vector(1,1,1),2.0,null,null,null);

			Ray[][] raylist = ca.produceRay(picWidth, picHeight, imgWidth,
					imgHeight, zoom);
			if (world.getBackground() == null) {
				System.out.println("error");
			}
			world.setRaylist(raylist);
			world.setIfShadowAndReflect(ifShadowAndReflect);
			world.setReflectionDepth(reflectionDepth);

			ImageProducer iPro = new ImageProducer(world);

			// divide the image for thread to process
			if (raylist.length <= threadNum || threadNum == 1) {

				// do not need multithread
				iPro.calPixels(0, raylist.length);

			} else {

				// calculatethe number of height one thread should calculate

				int part = raylist.length / threadNum;
				int restPart = raylist.length % part;

				int index;

				// Store the thread instance
				ArrayList<Thread> threadGroup = new ArrayList<Thread>();
				if (restPart == 0) {

					for (index = 0; index < threadNum; index++) {
						RayTracerThread rtt = new RayTracerThread(iPro, part
								* index, part * (1 + index));
						// creat multithread
						Thread t = new Thread(rtt);
						threadGroup.add(t);
						t.start();

					}

				} else {

					for (index = 0; index < threadNum; index++) {
						RayTracerThread rtt = new RayTracerThread(iPro, part
								* index, part * (1 + index));
						// creat multithread
						Thread t = new Thread(rtt);
						threadGroup.add(t);
						t.start();

					}
					iPro.calPixels(part * index, part * index + restPart);

				}
				// wait all the thread complete
				try {
					Iterator<Thread> itr = threadGroup.iterator();
					while (itr.hasNext()) {
						Thread instance = itr.next();
						instance.join();

					}

				} catch (Exception e) {
					e.printStackTrace();
				}

			}

			// form a colour array to get the result image
			Colour[][] colour = new Colour[raylist.length][raylist[0].length];
			for (int j = 0; j < raylist.length; j++) {
				for (int i = 0; i < raylist[0].length; i++) {
					colour[j][i] = iPro.getPixelsIndex(j, i);

				}
			}

			// write to a ppm file
			Bitmap bResult = new Bitmap("P6", raylist[0].length,
					raylist.length, 255, colour);

			BitmapIO bIO = new BitmapIO();
			bIO.writeBitmap(fileWrite, bResult);

		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
